module ysyx_23060189_AXI_Lite_arbiter #
(
  parameter addrwidth = 32,
  parameter datawidth = 32
)
(
  // Global
  input  wire                   ACLK,
  input  wire                   ARESETn,

  /* Master1 interface */
  // Write address channel
  input  wire                   AWVALID_MASTER_1,
  output reg                    AWREADY_MASTER_1,
  input  wire [addrwidth-1:0]   AWADDR_MASTER_1,
  input  wire [2:0]             AWPROT_MASTER_1,

  // Write data channel
  input  wire                   WVALID_MASTER_1,
  output reg                    WREADY_MASTER_1,
  input  wire [datawidth-1:0]   WDATA_MASTER_1,
  input  wire [datawidth/8-1:0] WSTRB_MASTER_1,

  // Write response channel
  output reg                    BVALID_MASTER_1,
  input  wire                   BREADY_MASTER_1,
  output reg  [1:0]             BRESP_MASTER_1,

  // Read address channel
  input  wire                   ARVALID_MASTER_1,
  output reg                    ARREADY_MASTER_1,
  input  wire [addrwidth-1:0]   ARADDR_MASTER_1,
  input  wire [2:0]             ARPROT_MASTER_1,

  // Read data channel
  output reg                    RVALID_MASTER_1,
  input  wire                   RREADY_MASTER_1,
  output reg  [datawidth-1:0]   RDATA_MASTER_1,
  output reg  [1:0]             RRESP_MASTER_1,

  /* Master2 interface */
  // Write address channel
  input  wire                   AWVALID_MASTER_2,
  output reg                    AWREADY_MASTER_2,
  input  wire [addrwidth-1:0]   AWADDR_MASTER_2,
  input  wire [2:0]             AWPROT_MASTER_2,

  // Write data channel
  input  wire                   WVALID_MASTER_2,
  output reg                    WREADY_MASTER_2,
  input  wire [datawidth-1:0]   WDATA_MASTER_2,
  input  wire [datawidth/8-1:0] WSTRB_MASTER_2,

  // Write response channel
  output reg                    BVALID_MASTER_2,
  input  wire                   BREADY_MASTER_2,
  output reg  [1:0]             BRESP_MASTER_2,

  // Read address channel
  input  wire                   ARVALID_MASTER_2,
  output reg                    ARREADY_MASTER_2,
  input  wire [addrwidth-1:0]   ARADDR_MASTER_2,
  input  wire [2:0]             ARPROT_MASTER_2,

  // Read data channel
  output reg                    RVALID_MASTER_2,
  input  wire                   RREADY_MASTER_2,
  output reg  [datawidth-1:0]   RDATA_MASTER_2,
  output reg  [1:0]             RRESP_MASTER_2,

  /* Slave interface */
  // Write address channel
  output reg                    AWVALID_SLAVE_1,
  input  wire                   AWREADY_SLAVE_1,
  output reg  [addrwidth-1:0]   AWADDR_SLAVE_1,
  output wire [2:0]             AWPROT_SLAVE_1,

  // Write data channel
  output reg                    WVALID_SLAVE_1,
  input  wire                   WREADY_SLAVE_1,
  output reg  [datawidth-1:0]   WDATA_SLAVE_1,
  output wire [datawidth/8-1:0] WSTRB_SLAVE_1,

  // Write response channel
  input  wire                   BVALID_SLAVE_1,
  output reg                    BREADY_SLAVE_1,
  input  wire [1:0]             BRESP_SLAVE_1,

  // Read address channel
  output reg                    ARVALID_SLAVE_1,
  input  wire                   ARREADY_SLAVE_1,
  output reg  [addrwidth-1:0]   ARADDR_SLAVE_1,
  output wire [2:0]             ARPROT_SLAVE_1,

  // Read data channel
  input  wire                   RVALID_SLAVE_1,
  output reg                    RREADY_SLAVE_1,
  input  wire [datawidth-1:0]   RDATA_SLAVE_1,
  input  wire [1:0]             RRESP_SLAVE_1
);

  // parameter define
  localparam IDEL    = 3'b001;
  localparam MASTER1 = 3'b010;
  localparam MASTER2 = 3'b100;

  // reg define
  reg [2 : 0] curr_status;
  reg [2 : 0] next_status;

  // wire define
  wire done = (BVALID_SLAVE_1 && BREADY_SLAVE_1) || (RVALID_SLAVE_1 && RREADY_SLAVE_1);

  // status machine
  always @(posedge ACLK) begin
    if (ARESETn == 0) curr_status <= IDEL;
    else curr_status <= next_status;
  end
  // status transfer
  always @(*) begin
    case (curr_status)
      IDEL:
        if (AWVALID_MASTER_1 || ARVALID_MASTER_1) next_status = MASTER1;
        // else if (ARVALID_MASTER_1 || ARVALID_MASTER_1) next_status = MASTER1;
        else if (AWVALID_MASTER_2 || ARVALID_MASTER_2) next_status = MASTER2;
        // else if (ARVALID_MASTER_2 || ARVALID_MASTER_2) next_status = MASTER2;
        else next_status = IDEL;

      MASTER1:
        if (done) next_status = IDEL; 
        else next_status = MASTER1;

      MASTER2:
        if (done) next_status = IDEL; 
        else next_status = MASTER2;

      default:
        next_status = IDEL;
    endcase
  end

  // process request of master 1 and master 2
  always @(*) begin
    case (curr_status)
      MASTER1: begin
        // Write address channel
        AWVALID_SLAVE_1 = AWVALID_MASTER_1;
        AWADDR_SLAVE_1  = AWADDR_MASTER_1;
        AWPROT_SLAVE_1  = AWPROT_MASTER_1;
        // Write data channel
        WVALID_SLAVE_1  = WVALID_MASTER_1;
        WDATA_SLAVE_1   = WDATA_MASTER_1;
        WSTRB_SLAVE_1   = WSTRB_MASTER_1;
        // Write response channel
        BREADY_SLAVE_1  = BREADY_MASTER_1;
        // Read address channel
        ARVALID_SLAVE_1 = ARVALID_MASTER_1;
        ARADDR_SLAVE_1  = ARADDR_MASTER_1;
        ARPROT_SLAVE_1  = ARPROT_MASTER_1;
        // Read data channel
        RREADY_SLAVE_1  = RREADY_MASTER_1;
      end 

      MASTER2: begin
        // Write address channel
        AWVALID_SLAVE_1 = AWVALID_MASTER_2;
        AWADDR_SLAVE_1  = AWADDR_MASTER_2;
        AWPROT_SLAVE_1  = AWPROT_MASTER_2;
        // Write data channel
        WVALID_SLAVE_1  = WVALID_MASTER_2;
        WDATA_SLAVE_1   = WDATA_MASTER_2;
        WSTRB_SLAVE_1   = WSTRB_MASTER_2;
        // Write response channel
        BREADY_SLAVE_1  = BREADY_MASTER_2;
        // Read address channel
        ARVALID_SLAVE_1 = ARVALID_MASTER_2;
        ARADDR_SLAVE_1  = ARADDR_MASTER_2;
        ARPROT_SLAVE_1  = ARPROT_MASTER_2;
        // Read data channel
        RREADY_SLAVE_1  = RREADY_MASTER_2;
      end

      default: begin
        // Write address channel
        AWVALID_SLAVE_1 = 1'b0;
        AWADDR_SLAVE_1  = 0;
        AWPROT_SLAVE_1  = 3'h0;
        // Write data channel
        WVALID_SLAVE_1  = 1'b0;
        WDATA_SLAVE_1   = 0;
        WSTRB_SLAVE_1   = 0;
        // Write response channel
        BREADY_SLAVE_1  = 0;
        // Read address channel
        ARVALID_SLAVE_1 = 1'b0;
        ARADDR_SLAVE_1  = 0;
        ARPROT_SLAVE_1  = 3'h0;
        // Read data channel
        RREADY_SLAVE_1  = 1'b0;
      end

    endcase
  end

  // process response of slave1 to master1
  always @(*) begin
    if (curr_status == MASTER1) begin
      // Write address channel
      AWREADY_MASTER_1 = AWREADY_SLAVE_1;
      // Write data channel
      WREADY_MASTER_1  = WREADY_SLAVE_1;
      // Write response channel
      BVALID_MASTER_1  = BVALID_SLAVE_1;
      BRESP_MASTER_1   = BRESP_SLAVE_1;
      // Read address channel
      ARREADY_MASTER_1 = ARREADY_SLAVE_1;
      // Read data channel
      RVALID_MASTER_1  = RVALID_SLAVE_1;
      RDATA_MASTER_1   = RDATA_SLAVE_1;
      RRESP_MASTER_1   = RRESP_SLAVE_1;
    end
    else begin
      // Write address channel
      AWREADY_MASTER_1 = 1'b0;
      // Write data channel
      WREADY_MASTER_1  = 1'b0;
      // Write response channel
      BVALID_MASTER_1  = 1'b0;
      BRESP_MASTER_1   = 2'b0;
      // Read address channel
      ARREADY_MASTER_1 = 1'b0;
      // Read data channel
      RVALID_MASTER_1  = 1'b0;
      RDATA_MASTER_1   = 0;
      RRESP_MASTER_1   = 2'b0;
    end
  end

  // process response of slave1 to master2
  always @(*) begin
    if (curr_status == MASTER2) begin
      // Write address channel
      AWREADY_MASTER_2 = AWREADY_SLAVE_1;
      // Write data channel
      WREADY_MASTER_2  = WREADY_SLAVE_1;
      // Write response channel
      BVALID_MASTER_2  = BVALID_SLAVE_1;
      BRESP_MASTER_2   = BRESP_SLAVE_1;
      // Read address channel
      ARREADY_MASTER_2 = ARREADY_SLAVE_1;
      // Read data channel
      RVALID_MASTER_2  = RVALID_SLAVE_1;
      RDATA_MASTER_2   = RDATA_SLAVE_1;
      RRESP_MASTER_2   = RRESP_SLAVE_1;
    end
    else begin
      // Write address channel
      AWREADY_MASTER_2 = 1'b0;
      // Write data channel
      WREADY_MASTER_2  = 1'b0;
      // Write response channel
      BVALID_MASTER_2  = 1'b0;
      BRESP_MASTER_2   = 2'b0;
      // Read address channel
      ARREADY_MASTER_2 = 1'b0;
      // Read data channel
      RVALID_MASTER_2  = 1'b0;
      RDATA_MASTER_2   = 0;
      RRESP_MASTER_2   = 2'b0;
    end
  end

endmodule
